import javax.swing.*;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.Random;
import java.util.Timer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class GUIEventGenerator extends JFrame
{	
//	private QueueProcessor qprocess = new QueueProcessor();
	
	private JFrame gui = new JFrame("Event Generator Interface");
	public static PriorityQueue queue = new PriorityQueue(20);
	
	private final static String newline = "\n";
	private JTextArea eventdisp;
	private static JTextField dispcount;
	private String logstring;
	
	//for event logging
	private static FileWriter fostream;
	private static FileReader fistream;
	private static BufferedWriter out;

	static DateFormat clockDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
	static Date clock;
	
	private boolean stop = false; //flag used to determine if event generator should be stopped
	private static boolean eventadded = false;
	
	public GUIEventGenerator()
	{
		
		gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		gui.setSize(500,500);
		gui.setVisible(true);
		
		gui.setLayout(new BoxLayout(gui.getContentPane(), BoxLayout.Y_AXIS));
		
		eventdisp = new JTextArea(2,15);
		eventdisp.setEditable( false );
		gui.add(eventdisp);
		
		//add textField with realtime arraycount
		JPanel count_disp_pan = new JPanel();
		count_disp_pan.setLayout(new FlowLayout());
		count_disp_pan.add(new JLabel("Current Queue Count"));
		dispcount = new JTextField(2);
//		dispcount.setAlignmentX(CENTER_ALIGNMENT);
		count_disp_pan.add(dispcount);
		gui.add(count_disp_pan);
		
		JPanel buttonp = new JPanel();
		buttonp.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10));
		
		JButton start = new JButton( "Start" );
		start.addActionListener(new StartButtonHandler());
		start.setAlignmentX(CENTER_ALIGNMENT);
		buttonp.add(start);
		
		JButton stop = new JButton( "Stop" );
		stop.addActionListener(new StopButtonHandler());
		stop.setAlignmentX(CENTER_ALIGNMENT);
		buttonp.add(stop);
		
		JButton view = new JButton( "View Event Log" );
		view.addActionListener(new ViewButtonHandler());
		view.setAlignmentX(CENTER_ALIGNMENT);
		buttonp.add(view);
		
		//add button panel to GUI
		gui.add(buttonp);
	}
	
	private class StartButtonHandler implements ActionListener
	{
		public void actionPerformed( ActionEvent event )
		{
			stop = false;	//clear stop eventgenerator flag
			
			logstring = "Event Generator started.";
			eventdisp.setText(clockDateFormat.format(clock) + ": " + logstring + newline);
			clock = new Date();
			logevent(clockDateFormat.format(clock) + ": " + logstring + newline);
			
			QueueProcessingThread processRunnable = new QueueProcessingThread();
			Thread processThread = new Thread(processRunnable);
			processThread.start();
			
			QueueCountUpdateThread updateRunnable = new QueueCountUpdateThread();
			Thread updateThread = new Thread(updateRunnable);
			updateThread.start();
		}
	}
	
	private class QueueCountUpdateThread implements Runnable
	{
		public void run()
		{
			while(true && queue.eventCount >= 0)
			{
				if(eventadded == true)
				{
					dispcount.setText(Integer.toString(queue.eventCount));
				}
			}
		}
	}
	
	private class QueueProcessingThread implements Runnable
	{
		public void run()
		{
			//process queue
			do
			{	
				Event e = queue.getEvent();
				System.out.println("EVENT PR: " + e.PR + " INF: " + e.INF + newline);
				eventdisp.append(clockDateFormat.format(clock) + ": " + "EVENT PR: " + e.PR + " INF: " + e.INF + newline);
				clock = new Date();
				logevent(clockDateFormat.format(clock) + ": " + "EVENT PR: " + e.PR + " INF: " + e.INF + newline);
				
				if(queue.queueFull() == false && stop == false)
				{
					//add new events
					//assign random probability between 1 and 30
					int min = 1;
					int max = 30;
					int origpr = min + (int)(Math.random() * ((max - min) + 1));
					EventGenerator generator = new EventGenerator(origpr);
					if (generator.newEvent.type != -1) 
					{ 
						boolean r = queue.insertEvent(generator.newEvent);
						if (r == true) {
							//determine which event occured
							String eventType = null;
							if (generator.newEvent.type == 1) { eventType = "Random-A Generated Event"; }
							else if (generator.newEvent.type == 2) { eventType = "Random-B Generated Event"; }
							
							System.out.println("Insertion of new event successful");
							clock = new Date();
							eventdisp.append(clockDateFormat.format(clock) + ": " + eventType + " with priority " + generator.newEvent.PR + " inserted into queue.\n");
							logevent(clockDateFormat.format(clock) + ": " + eventType + " with priority " + generator.newEvent.PR + " inserted into queue.\n");
							
							dispcount.setText(Integer.toString(queue.eventCount));
							eventadded = true;
						} 
						else {
							System.out.println("Insertion of new event failed");
							clock = new Date();
							eventdisp.append(clockDateFormat.format(clock) + ": New event failed to be inserted into Priority Queue\n");
							logevent(clockDateFormat.format(clock) + ": New event failed to be inserted into Priority Queue\n");
						}
					}
					else	//log that no event was generated
					{
						System.out.println("No new event generated.\n");
						clock = new Date();
						eventdisp.append(clockDateFormat.format(clock) + ": No new event generated.\n");
						logevent(clockDateFormat.format(clock) + ": No new event generated.\n");
					}
					
					
					//ask user if he or she would like to add an event to the queue
					int enterevent = JOptionPane.showConfirmDialog(null, "Would you like to add a new event to the queue?", null, JOptionPane.YES_NO_OPTION);
					if( enterevent == JOptionPane.YES_OPTION )
					{
						Event userEvent = generator.GetUserEvent();
						boolean r = queue.insertEvent(userEvent);
						if (r == true) {
							System.out.println("Insertion of new event successful");
							clock = new Date();
							eventdisp.append(clockDateFormat.format(clock) + ": " + "User Generated Event with priority " + userEvent.PR + " inserted into queue.\n");
							logevent(clockDateFormat.format(clock) + ": " + "User Generated Event with priority " + userEvent.PR + " inserted into queue.\n");
							
							dispcount.setText(Integer.toString(queue.eventCount));
							eventadded = true;
						} 
						else {
							System.out.println("Insertion of new event failed");
							clock = new Date();
							eventdisp.append(clockDateFormat.format(clock) + ": " + "User Generated Event failed to be inserted into Priority Queue\n");
							logevent(clockDateFormat.format(clock) + ": " + "User Generated Event failed to be inserted into Priority Queue\n");
						}
					}
					
				}
				
				
				//delay 1 second
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
			} while (queue.eventCount != 0);
			
			System.out.println("Priority Queue Depleted");
			clock = new Date();
			eventdisp.append(clockDateFormat.format(clock) + ": " + "Priority Queue Depleted\n");
			logevent(clockDateFormat.format(clock) + ": " + "Priority Queue Depleteds\n");
		}
	}
	
	private class StopButtonHandler implements ActionListener
	{
		public void actionPerformed( ActionEvent event )
		{
			logstring = "Event Generator Stopped; running through remaining events...";
			eventdisp.append(clockDateFormat.format(clock) + ": " + logstring + newline);
			clock = new Date();
			logevent(clockDateFormat.format(clock) + ": " + logstring + newline);
			
			stop = true;
		}
	}
	
	private class ViewButtonHandler implements ActionListener
	{
		public void actionPerformed( ActionEvent event )
		{
			JFrame eventlog = new JFrame("Event Log");
			eventlog.setSize(500,500);
			eventlog.setVisible(true);
			
			JTextArea log = new JTextArea(2,15);
			log.setEditable(false);
			JScrollPane scrollPane = new JScrollPane(log);
			scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
			eventlog.setPreferredSize(new Dimension(450,110));
			eventlog.add(scrollPane, BorderLayout.CENTER);
			
			//add components to this panel
			eventlog.add(log);
			
			//read from file and populate text area
			try
			{
				fistream = new FileReader("eventlog.txt");
				BufferedReader in = new BufferedReader(fistream);
				String line;
				
				boolean eof = false;
				while (eof == false)
				{
					line = in.readLine();
					if (line != null) { log.append(line + newline); }
					else { eof = true; } 
				}
				in.close();
			}
			catch (IOException e)
			{
				System.err.println("Error: " + e.getMessage());
			}
		}
	}
	
	public static void logevent(String message)
	{
		try
		{
			fostream = new FileWriter("eventlog.txt", true);
			out = new BufferedWriter(fostream); 
			out.write(message);
			
			out.close();
		}
		catch (IOException e)
		{
			System.err.println("Error: " + e.getMessage());
		}
	}
	
	public static String generateString()
	{
		//generate random string of 5 characters
		int strSize = 5;
		char[] info = new char[strSize];
		String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		Random randint = new Random();
		for(int i = 0; i < strSize; i++)
		{
			info[i] = chars.charAt(randint.nextInt(chars.length()));
		}
		return new String(info);
	}
	
	public void wait(int sec)
	{
		long t0, t1;
		t0 = System.currentTimeMillis();
		do
		{
			t1 = System.currentTimeMillis();
		} while (t1-t0 < 1000*sec);
	}
	
	public static void main( String[] args )
	{
		//clear contents of log file
		try
		{
			File prevlog = new File("eventlog.txt");
			prevlog.delete();
		}
		catch (Exception e)
		{
			System.err.println("Error: " + e.getMessage());
		}
		
		GUIEventGenerator  gui = new GUIEventGenerator();
		
		//initialize priority queue with random events of random priority
		for (int i = 0; i < 20; i++) {
			Event e = new Event();
			
			//assign random probability between 1 and 30
			int min = 1;
			int max = 30;
			int rp = min + (int)(Math.random() * ((max - min) + 1));
			e.PR = rp;
			
			//initialize first 20 events with random strings
			e.INF = generateString();
			
			boolean r = queue.insertEvent(e);
			if (r == true) {
				System.out.println("Insertion " + i + " successful");
				clock = new Date();
				logevent(clockDateFormat.format(clock) + ": "	 + "Initial Event inserted into Priority Queue\n");
				
				//update array count
//				dispcount.setText(Integer.toString(queue.eventCount));
				eventadded = true;
			} 
			else {
				System.out.println("Insertion failed");
				clock = new Date();
				logevent(clockDateFormat.format(clock) + ": " + "Initial Event failed to be inserted into Priority Queue\n");
			}
		}
	}
}
